#include "mcu_mmsg.h"
#include "fifo.h"
#include "mcu_clib.h"

static DWORD McuModbusBytes2Long(BYTE byteBuf[])
{
    return((byteBuf[0] << 24) + (byteBuf[1] << 16) + (byteBuf[2] << 8) + byteBuf[3]);
}

static void McuModbusLong2Bytes(BYTE byteBuf[], DWORD dw)
{
    byteBuf[0] = (BYTE)((dw >> 24) & 0x00FF);
    byteBuf[1] = (BYTE)((dw >> 16) & 0x00FF);
    byteBuf[2] = (BYTE)((dw >> 8) & 0x00FF);
    byteBuf[3] = (BYTE)(dw & 0x00FF);
}

McuMmsgOut::McuMmsgOut(BYTE slaveAddr): Tape()
{
    m_slaveAddr = slaveAddr;
    m_regAddr = 0;
}

McuMmsgOut::McuMmsgOut(BYTE slaveAddr, DWORD bigSize) : Tape(bigSize)
{
    m_slaveAddr = slaveAddr;
    m_regAddr = 0;
}

BOOL McuMmsgOut::CopyMmsgOut(McuMmsgOut* pSrcMsg)
{
    m_slaveAddr = pSrcMsg->m_slaveAddr;
    m_regAddr = pSrcMsg->m_regAddr;
    return(Tape::Copy(pSrcMsg));
}

void McuMmsgOut::_SetReading(WORD startRegAddr, DWORD numOfReg)
{
    m_regAddr = startRegAddr;

    _EnsureSize(8, 8);
    m_bBuffer[0] = m_slaveAddr;
    m_bBuffer[1] = 0x03;
    m_bBuffer[2] = HIBYTE(startRegAddr);
    m_bBuffer[3] = LOBYTE(startRegAddr);
    m_bBuffer[4] = HIBYTE(numOfReg);
    m_bBuffer[5] = LOBYTE(numOfReg);

    WORD crc = McuModbusCrc(m_bBuffer, 6);
    m_bBuffer[6] = HIBYTE(crc);
    m_bBuffer[7] = LOBYTE(crc);
    m_len = 8;
}

void McuMmsgOut::SetReadingParam(WORD regAddr)
{
    _SetReading(regAddr, 1);
}

void McuMmsgOut::SetReadingLongParam(WORD regAddr)
{
    _SetReading(regAddr, 2);
}

void McuMmsgOut::SetWritingParam(WORD regAddr, WORD param)
{
    m_regAddr = regAddr;

    _EnsureSize(8, 8);
    m_bBuffer[0] = m_slaveAddr;
    m_bBuffer[1] = 0x06;
    m_bBuffer[2] = HIBYTE(regAddr);
    m_bBuffer[3] = LOBYTE(regAddr);
    m_bBuffer[4] = HIBYTE(param);
    m_bBuffer[5] = LOBYTE(param);

    WORD crc = McuModbusCrc(m_bBuffer, 6);
    m_bBuffer[6] = HIBYTE(crc);
    m_bBuffer[7] = LOBYTE(crc);
    m_len = 8;
}

void McuMmsgOut::SetWritingLongParam(WORD regAddr, DWORD dwParam)
{
    m_regAddr = regAddr;

    _EnsureSize(16);
    m_bBuffer[0] = m_slaveAddr;
    m_bBuffer[1] = 0x10;
    m_bBuffer[2] = HIBYTE(regAddr);
    m_bBuffer[3] = LOBYTE(regAddr);
    m_bBuffer[4] = 0;
    m_bBuffer[5] = 2;
    m_bBuffer[6] = 4;

    DWORD writeLen = 7;
    McuModbusLong2Bytes(m_bBuffer + writeLen, dwParam);
    writeLen += 4;

    WORD crc = McuModbusCrc(m_bBuffer, writeLen);
    m_bBuffer[writeLen++] = HIBYTE(crc);
    m_bBuffer[writeLen++] = LOBYTE(crc);
    m_len = writeLen;
}





void  McuMmsgOut::SetCalling(WORD funcId, WORD instanceId, NPack* pArgPack)
{
    m_regAddr = instanceId;             // ʽĴַ

    DWORD argLen = pArgPack == NULL ? 0 : pArgPack->Length();
    _EnsureSize(8 + argLen);
    m_bBuffer[0] = m_slaveAddr;
    m_bBuffer[1] = 0x64;
    m_bBuffer[2] = HIBYTE(funcId);
    m_bBuffer[3] = LOBYTE(funcId);
    m_bBuffer[4] = HIBYTE(instanceId);
    m_bBuffer[5] = LOBYTE(instanceId);
    if (pArgPack != NULL) {
        memcpy_s(m_bBuffer + 6, m_size - 6, pArgPack->Buffer(), argLen);
    }

    DWORD writeLen = 6 + argLen;
    WORD crc = McuModbusCrc(m_bBuffer, writeLen);
    m_bBuffer[writeLen++] = HIBYTE(crc);
    m_bBuffer[writeLen++] = LOBYTE(crc);
    m_len = writeLen;
}




McuMmsgIn::McuMmsgIn(void) : Tape()
{
}

McuMmsgIn::McuMmsgIn(DWORD bigSize) : Tape(bigSize)
{
}

DWORD McuMmsgIn::Import(const BYTE* recvCache, DWORD cacheLen)
{
    if(Tape::Import(recvCache, cacheLen) == 0) {
        return(0);
    }

    WORD rightCrc = McuModbusCrc(m_bBuffer, m_len - 2);
    WORD returnCrc = (m_bBuffer[m_len - 1] + (m_bBuffer[m_len - 2] << 8));
    if (rightCrc != returnCrc) {
        m_len = 0;
    }
    return(m_len);
}

DWORD McuMmsgIn::GetReadDataLen(void)
{
    BYTE  funcCode = m_bBuffer[1];
    DWORD dataLen = m_bBuffer[2];
    return (funcCode == 0x03 ? dataLen : 0);
}

DWORD McuMmsgIn::GetWrittenDataLen(void)
{
    BYTE  funcCode = m_bBuffer[1];
    if (funcCode == 0x06) {
        return(2);
    }
    else if (funcCode == 0x10) {
        return(((m_bBuffer[4] << 8) + m_bBuffer[5]) * 2);
    }
    else {
        return(0);
    }
}

BOOL McuMmsgIn::GetReadParam(WORD* pParam)
{
    if (GetReadDataLen() == 2) {
        *pParam = (m_bBuffer[3] << 8) + m_bBuffer[4];
        return(TRUE);
    }
    else {
        return(FALSE);
    }
}

BOOL McuMmsgIn::GetReplied(Ndata* pReturnNdata)
{
    if (m_len > 8) {
        pReturnNdata->ImportN(m_bBuffer + 6);
        return(TRUE);
    }
    else {
          pReturnNdata->SetNull();
        return(FALSE);
    }
}
BOOL McuMmsgIn::GetReadLongParam(DWORD* pLongParam)
{
    if (GetReadDataLen() == 4) {
        *pLongParam = McuModbusBytes2Long(m_bBuffer + 3);
        return(TRUE);
    }
    else {
        return(FALSE);
    }
}



